#pragma once
#include <utility>
#include <vector>
#include <set>
#include <queue>
#include <string>
#define uint unsigned int

using namespace std; 

class Graph
{
public:
	class Edge {
	private:
		uint _first;
		uint _second;
		int _cost;
	public:
		// Constructors & Destructors
		Edge(uint first, uint second);
		Edge(uint first, uint second, int cost);
		Edge(const Edge& e);
		~Edge(void);

		// Getters & Setters
		bool setCost(int cost);
		int getCost(void) const;
		uint getFirst(void) const;
		uint getSecond(void) const;

		// Operator Overloading
		bool operator== (Edge const& edge) const;
		bool operator!= (Edge const& edge) const;
		bool operator<  (Edge const& edge) const;
		bool operator>  (Edge const& edge) const;
		Edge& operator= (Edge const& edge);

		// To String Function
		std::string toString(void);
	};

// Graph class interface:
private:
	int _vertNR;
	set<bool> _verts;
	vector<uint> _inDegree;
	vector<uint> _outDegree;
	vector< set<Edge> > _edges;
	vector< set<Edge> > _edgesInverted;

public:
	Graph(void);											
	Graph(uint vertNR);										
	~Graph(void);											

	void setVertNumber(int vertNR); 						
	int getVertNumber(void) const; 							
	Edge* getEdge(uint first, uint second) const;			
	int getCost(const Edge& edge) const;					
	int getCost(uint first, uint second) const;				
	bool setCost(Edge& edge, int cost);						
	bool setCost(uint first, uint second, int cost);		

	uint getOutDegree(uint vert) const;						
	uint getInDegree(uint vert) const;						

	vector<uint> iterateOut(uint vert);
	vector<uint> iterateIn (uint vert);

	pair<int,int> getEndpoints(Edge& edge) const;			

	bool addEdge(uint first, uint second);					
	bool addEdge(uint first, uint second, int cost);		
	bool removeEdge(uint first, uint second);				
	bool removeEdge(Edge& edge);							

	bool isEmpty(void);										
	bool isEdge(uint first, uint second);					

	bool readGraph(const string fileName);
	vector<uint> BFS(uint first, uint last);
};